﻿/*
 * Erstellt mit SharpDevelop.
 * Benutzer: Kai Patrick
 * Datum: 21.04.2008
 * Zeit: 17:22
 * 
 * Sie können diese Vorlage unter Extras > Optionen > Codeerstellung > Standardheader ändern.
 */

using System;
using System.Collections.Generic;
using System.Xml;
using System.IO;
using ICSharpCode.SharpZipLib.Zip;

namespace Gamadus.Builder
{
	/// <summary>
	/// Description of ResourceMgr.
	/// </summary>
	public class ResourceMgr : Gamadus.Core.SingletonManager<ResourceMgr>
	{
		List<Object> objects = new List<Object>();
		string IDstring = "";
		string setupString = "Room rm;\n";
		string populateString = "";
//		string resourceHeader = "using Gamadus.Engine;\npartial class Game{\n"+
//			"static void LoadSettings(){\n"+
//			"Engine.Instance.GameSettings[Setting.AllowESC] = true;\n"+
//			"Engine.Instance.GameSettings[Setting.AllowF4] = true;\n"+
//			"Engine.Instance.GameSettings[Setting.AllowCloseButton] = true;\n"+
//			"Engine.Instance.GameSettings[Setting.StartFullScreen] = false;\n}";
		
		public bool Load(string file)
		{
			try
			{
				File.Delete(DirectoryMgr.Instance.TempDir+"game.xml");
				ZipInputStream zip = new ZipInputStream(new StreamReader(file).BaseStream);
				ZipEntry curEntry;
				while ((curEntry = zip.GetNextEntry()) != null) 
			    {
					Console.WriteLine("Zip entry found: "+curEntry.Name);
					if(curEntry.Name == "game.xml")
					{
						ReadZipEntry(zip,DirectoryMgr.Instance.TempDir+"game.xml");
					}
					else
					{
						//TODO: read file resources
						//ReadZipEntry(zip,TempDir+curEntry.Name);
					}
			    }
				
				if(!File.Exists(DirectoryMgr.Instance.TempDir+"game.xml"))
					throw new ArgumentException(file+" is not a valid Gamadus project file: Doesn't contain game.xml");
				
				XmlDocument xml = new XmlDocument();
				xml.Load(DirectoryMgr.Instance.TempDir+"game.xml");
	        	if(xml.ChildNodes.Count < 2 || xml.ChildNodes[1].Name != "GamadusProject")
	        	{
	        		throw new ArgumentException(file+" is not a valid Gamadus project file: root tag is not GamadusProject");
	        	}
	        	XmlElement rootElement = xml.ChildNodes[1] as XmlElement;
	        	if(!rootElement.HasAttribute("Version"))
	        	{
	        		throw new ArgumentException(file+" is not a valid Gamadus project file: GamadusProject has no Version attribute");
	        	}
	        	foreach(XmlElement element in rootElement.ChildNodes)
	        	{
	        		switch(element.Name)
	        		{	        				
	        			case "Resources":
	        				foreach(XmlElement child in element.ChildNodes)
	        				{
	        					if(child.Name != "Resource" ||
	        					   !child.HasAttribute("Name") ||
	        					   !child.HasAttribute("Type") ||
	        					   !child.HasAttribute("ID"))                    
	        					{
	        						continue;
	        					}
	        					string name = child.Attributes["Name"].InnerText;
	        					string id = child.Attributes["ID"].InnerText;
	        					string type = child.Attributes["Type"].InnerText;
	        					IDstring += "public static real "+name+" = "+id+";\n";
	        					switch(type)
	        					{
	        						case "Object":
	        							setupString += "ResourceMgr.Instance.CreateObject("+name+", typeof("+name+"));\n";
	        							string constructor = "public "+name+"(int id, double x, double y, Room room) : base(id, x, y, room){\n";
	        							constructor += ReadSettings(child,"this.", EngineMgr.Instance.ObjectVars)+"Create();\n}";
	        							Gamadus.Builder.Object obj = new Gamadus.Builder.Object(constructor);
	        							objects.Add(obj);
	        							break;
	        						case "Room":
	        							setupString += "rm = ResourceMgr.Instance.CreateRoom("+name+");\n";
	        							setupString += ReadSettings(child, "rm.", EngineMgr.Instance.RoomVars);
	        							if(child.GetElementsByTagName("Instances").Count > 0)
	        							{
	        								populateString += "if(room.ID == "+name+"){\n";
											XmlElement instanceChild = (XmlElement)element.GetElementsByTagName("Instances")[0];
											foreach(XmlElement inst in instanceChild.ChildNodes)
											{
												if(!inst.HasAttribute("ObjectID") || !inst.HasAttribute("X") || !inst.HasAttribute("Y"))
													continue;
												
												populateString += "ResourceMgr.Instance.CreateInstance("+inst.Attributes["ObjectID"].InnerText+","+inst.Attributes["X"].InnerText+","+inst.Attributes["Y"].InnerText+",room);";
											}
											populateString += "}\n";
	        							}
	        							break;
	        					}
	        				}
	        				break;
	        		}
	        	}
	        	Console.WriteLine("====================================\n"+setupString+"\n=======================================================\n"+populateString+"\n=======================================================");
	        	return true;
			}
			catch(ArgumentException e)
			{
				Console.WriteLine("Error occurred while loading the project: "+e.Message);
				return false;
			}
			catch(FileNotFoundException)
			{
				Console.WriteLine("File "+file+" does not exist");
				return false;
			}
		}
			
		void ReadZipEntry(ZipInputStream zip, string target)
		{
			FileStream sw = File.Create((target));
			int nBytes = 2048;
			byte[] data = new byte[2048];
			while((nBytes = zip.Read(data, 0, data.Length))  > 0)
			{
				sw.Write(data,0,nBytes);
			}
			sw.Close();
		}
		
		string ReadSettings(XmlElement node, string prefix, List<string> keys)
		{
			string str = "";
			XmlNodeList list = node.GetElementsByTagName("Settings");
			if(list.Count == 0)
			{
				throw new ArgumentException("One or more Resource tags don't contain a Settings tag");
			}
		
			foreach(XmlElement setting in ((XmlElement)list[0]).GetElementsByTagName("Set"))
			{
				if(!setting.HasAttribute("Name") || setting.ChildNodes.Count == 0)
					continue;
				
				string key = setting.Attributes["Name"].InnerText;
				if(!keys.Contains(key))
					Console.WriteLine("Warning: Ignoring key "+key);
				string val = ReadObject(setting.ChildNodes[0] as XmlElement);
				str += prefix+key+" = "+val+";\n";
			}
			return str;
		}
		
		string ReadObject(XmlElement element)
		{
			if(element.Name != "Object" || !element.HasAttribute("Type"))
			{
				throw new ArgumentException("Can't read xml object");
			}
			
			switch(element.Attributes["Type"].InnerText)
			{
				case "Int32":
					return element.InnerText;
				case "String":
					return "\""+element.InnerText+"\"";
				case "Boolean":
					return element.InnerText.ToLower();
				case "Color":
					return "System.Drawing.Color.FromArgb("+element.ChildNodes[0].Attributes["R"].InnerText+", "+element.ChildNodes[0].Attributes["G"].InnerText+", "+element.ChildNodes[0].Attributes["B"].InnerText+", "+element.ChildNodes[0].Attributes["A"].InnerText+")";
				default:
					throw new ArgumentException("Unknown object definition found in xml");
			}
		}
	}
}
